package soar.test.yaml;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.yaml.snakeyaml.DumperOptions;
//import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import soar.test.yaml.config.AppConfig;
//import soar.test.yaml.config.MySQL;
//import soar.test.yaml.config.Site;

public class App
{
    public static AppConfig config;
    
    public static void main(String[] args)
    {
        String config_file = "config/app.yaml";
        if (args.length > 1)
        {
            config_file = args[0];
        }
        new App().run(config_file);
    }

    private void run(String config_file)
    {
        try
        {
            String split = "========================================";
            System.out.println(split);

            test_generate();
            System.out.println(split);

            test_load();
            System.out.println(split);

            test_config(config_file);
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.err.println(String.format("fail: %s", e));
        }
    }

    private void test_generate() throws Exception
    {
        String split = "-------------------------------------------";

        Map<String, Object> map = new HashMap<>();
        map.put("name", "Tom");
        map.put("age", 40);
        List<Map<String, Object>> children = new ArrayList<>();
        Map<String, Object> c1 = new HashMap<>();
        c1.put("name", "Jack");
        c1.put("age", 10);
        Map<String, Object> c2 = new HashMap<>();
        c2.put("name", "Rose");
        c2.put("age", 8);
        children.add(c1);
        children.add(c2);
        map.put("children", children);
        Map<String, Object> salary = new HashMap<>();
        salary.put("basic", 10000);
        salary.put("bonus", new int[] { 1000, 2000 });
        map.put("salary", salary);
        Yaml yaml = new Yaml();
        System.out.println(yaml.dump(map));

        System.out.println(split);

        Person p = new Person();
        p.setName("约翰");
        p.setAge(37);
        Person s = new Person();
        s.setName("简");
        s.setAge(35);
        p.setSpouse(s);
        Person[] c = { new Person(), new Person() };
        c[0].setName("吉姆");
        c[0].setAge(8);
        c[1].setName("卡莉");
        c[1].setAge(8);
        p.setChildren(c);

        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        yaml = new Yaml(options);
        String dump = yaml.dump(p);
        System.out.println(dump);
    }

    @SuppressWarnings("unchecked")
    private void test_load() throws Exception
    {
        String split = "-------------------------------------------";

        Yaml yaml = new Yaml();

        String doc = "";
        doc += "- Hesperiidae\n";
        doc += "- Papilionidae\n";
        doc += "- Apatelodidae\n";
        doc += "- Epiplemidae\n";
        String[] arr = (String[]) yaml.loadAs(doc, String[].class);
        Stream.of(arr).forEach(System.out::println);

        System.out.println(split);

        doc = "";
        doc += "port:    5000\n";
        doc += "mysql:\n";
        doc += "    db1:\n";
        doc += "        user: dbuser\n";
        doc += "        password: dbuser\n";
        doc += "    db2:\n";
        doc += "        user: dbuser2\n";
        doc += "        password: dbuser2\n";
        doc += "site:\n";
        doc += "    - name: baidu\n";
        doc += "      url: www.baidu.com\n";
        doc += "    - name: google\n";
        doc += "      url: www.google.com\n";
        System.out.println(doc);
        System.out.println(split);

        Iterable<Object> o = yaml.loadAll(doc);
        o.forEach(System.out::println);
        System.out.println(split);

        Map<String, Object> root = (Map<String, Object>) yaml.load(doc);
        root.forEach((k, v) -> System.out.println(k + " -> " + v));
        System.out.println(split);

        System.out.println("port");
        int port = (Integer) root.get("port");
        System.out.println("    port: " + port);
        System.out.println(split);

        System.out.println("mysql");
        Map<String, Object> mysql = (Map<String, Object>) root.get("mysql");
        mysql.forEach((k, v) -> {
            System.out.println("    " + k + ": " + v);
            ((Map<String, Object>) v).forEach((k1, v1) -> System.out
                    .println("        " + k1 + ": " + v1));
        });
        System.out.println(split);

        System.out.println("site");
        List<Object> site = (List<Object>) root.get("site");
        site.forEach(x -> {
            System.out.println("    " + x);
            ((Map<String, Object>) x).forEach((k, v) -> System.out
                    .println("        " + k + ": " + v));
        });
    }

    private void test_config(String config_file) throws Exception
    {
        Constructor constructor = new Constructor(AppConfig.class);
        // 以下并不需要
//         TypeDescription desc = new TypeDescription(AppConfig.class);
//         desc.putMapPropertyType("mysql", String.class, MySQL.class);
//         constructor.addTypeDescription(desc);
//         desc = new TypeDescription(AppConfig.class);
//         desc.putListPropertyType("site", Site.class);
//         constructor.addTypeDescription(desc);
        Yaml yaml = new Yaml(constructor);
        InputStream in = new FileInputStream(config_file);
        App.config = (AppConfig) yaml.load(in);
        in.close();

        System.out.println("port: " + App.config.getPort());
        System.out.println("mysql: ");
        config.getMysql().forEach((k, v) -> {
            System.out.println("    " + k + ":");
            System.out.println("        url: " + v.getUrl());
            System.out.println("        username: " + v.getUsername());
            System.out.println("        password: " + v.getPassword());
        });
        System.out.println("site: ");
        // Arrays.asList(app_config.getSite()).forEach(v->{
        App.config.getSite().forEach(v -> {
            System.out.println("    []");
            System.out.println("        name: " + v.getName());
            System.out.println("        url: " + v.getUrl());
            System.out.println("        appid: " + v.getAppid());
            System.out.println("        appkey: " + v.getAppkey());
        });
    }
}

class Person
{
    private String name;
    private int age;
    private Person spouse;
    private Person[] children;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public Person getSpouse()
    {
        return spouse;
    }

    public void setSpouse(Person spouse)
    {
        this.spouse = spouse;
    }

    public Person[] getChildren()
    {
        return children;
    }

    public void setChildren(Person[] children)
    {
        this.children = children;
    }

}
